#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <sys/time.h>
#include <pthread.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>

#include<openssl/md5.h>
#include "redisconn.h"

#define HOST "127.0.0.1"
#define PORT 16379

int thread_running_count = 0;
int thread_close_count = 0;
int thread_count = 6;
long thread_time_val = 0;
struct timeval thread_start_time, thread_end_time;
struct thread_info {
    int index;
    pthread_t tid;
    redis_conn_ctx *ctx;
};

void* thread_search_performance(void *arg)
{
    redis_conn_result *r = NULL;
    int i = 0;
    int max_times = 500000;
    int ret = 0;

    struct thread_info *info = arg;
    redis_conn_ctx *ctx = info->ctx;
    
    char *search_cmd = "HMGET 1:url:1 url:aaa/";
    int search_cmd_len = strlen(search_cmd);

    ret = __sync_fetch_and_add(&thread_running_count,1);
    if  (ret == 0) {
        gettimeofday(&thread_start_time, NULL);
    }

    for (i = 0; i < max_times; i++) {
        r = redisconn_run_command(ctx, search_cmd, search_cmd_len); 
        if (!r) {
            printf("run command failed:%s\n", search_cmd);
            goto out;
        }
        //redisconn_print_result(r);
        redisconn_free_result(r);
    }
    ret = __sync_add_and_fetch(&thread_close_count,1);
    if  (ret == thread_count) {
        gettimeofday(&thread_end_time, NULL);
        thread_time_val = (thread_end_time.tv_sec - thread_start_time.tv_sec) * 1000 + (thread_end_time.tv_usec - thread_start_time.tv_usec)/1000;
        if (thread_time_val > 0) {
            printf("total time is :%lf(seconds), count:%d, times/perseconds:%ld\n", 
                (double) thread_time_val/1000, max_times*thread_count, (max_times*1000/thread_time_val)*thread_count);
        } else {
            printf("run time too short\n");
        }
        printf("<===========end performance test using cmd:%s\n", search_cmd);
    }

out:
    return NULL;
}

int main()
{
    redis_conn_ctx *ctx = NULL;
    redis_conn_result *r = NULL;
    int i = 0;
    int max_times = 10000;
    int md5_max_times = 10000000;
    long time_val = 0;
    struct timeval start_time, end_time;
    int pid;

    int tid[64];
    struct thread_info tinfo[64];

    ctx = redisconn_connect(HOST,PORT);
    if (!ctx) {
        printf("connect failed\n");
        return -1;
    }

    char *cmd[] = {
        "HMSET 1:url:1 path '/' parentid 0 url:aaa/ 1 argcount 10",
        "HMSET 1:url:1 url:aaa/ '{mathmodel:{kmeans:0}}'"
        "HMGET 1:url:1 path",
        "HMGET 1:url:1 parentid",
        "HMGET 1:url:1 url:aaa/",
        "HMGET 1:url:1 argcount",
        "HINCRBY 1:url:1 argcount 1",
        "HMGET 1:url:1 argcount",
        "HMSET chinesehash '中文field' '中文value'",
        "HMGET chinesehash '中文field'",
    };

    for (i = 0; i < sizeof(cmd)/sizeof(cmd[0]); i++) {
        printf("run command:%s\n", cmd[i]);
        r = redisconn_run_command(ctx, cmd[i], strlen(cmd[i])); 
        if (!r) {
            printf("run command failed:%s\n", cmd[i]);
            goto out;
        }
        redisconn_print_result(r);
        redisconn_free_result(r);
    }

    sleep(100);
    //===> test performance using thread
    for (i = 0; i < thread_count; i++) {
        memset(&tinfo[i], 0x0, sizeof(struct thread_info));
        tinfo[i].index = i;
        tinfo[i].ctx = redisconn_connect(HOST,PORT);
        if (!tinfo[i].ctx) {
            printf("connect failed\n");
            return -1;
        }
    }
    for (i = 0; i < thread_count; i++) {
        if (pthread_create(&tinfo[i].tid, NULL, thread_search_performance, &tinfo[i])) {
            printf("pthread create failed\n");
            return -1;
        }
    }
    for (i = 0; i < thread_count; i++) {
        pthread_join(tinfo[i].tid,NULL);
        redisconn_close(tinfo[i].ctx);
    }
    //<=== test performance using thread


    char *search_cmd = "HMGET 1:url:1 url:aaa/";
    int search_cmd_len = strlen(search_cmd);
    printf("===========>start performance test using cmd:%s\n", search_cmd);
    gettimeofday(&start_time, NULL);
    for (i = 0; i < max_times; i++) {
    //for (i = 0; i < 1; i++) {
        r = redisconn_run_command(ctx, search_cmd, search_cmd_len); 
        if (!r) {
            printf("run command failed:%s\n", search_cmd);
            goto out;
        }
        //redisconn_print_result(r);
        redisconn_free_result(r);
    }
    gettimeofday(&end_time, NULL);
    time_val = (end_time.tv_sec - start_time.tv_sec) * 1000 + (end_time.tv_usec - start_time.tv_usec)/1000;
    if (time_val > 0) {
        printf("total time is :%lf(seconds), count:%d, times/perseconds:%ld\n", 
           (double) time_val/1000, max_times, (max_times*1000/time_val));
    } else {
        printf("run time too short\n");
    }
    printf("<===========end performance test using cmd:%s\n", search_cmd);


    char *search_url = "https://www.cnblogs.com/silent2012/p/4514901.html";
    int search_url_len = strlen(search_url);
    MD5_CTX md5_ctx;
    unsigned char md[16];
    printf("===========>start performance test md5 for url:%s\n", search_url);
    gettimeofday(&start_time, NULL);
    for (i = 0; i < md5_max_times; i++) {
        if (0) {
            MD5_Init(&md5_ctx);
            MD5_Update(&md5_ctx,search_url, search_url_len);
            MD5_Final(md,&md5_ctx);
        } else {
            MD5(search_url, search_url_len, md);
        }
    }
    gettimeofday(&end_time, NULL);
    time_val = (end_time.tv_sec - start_time.tv_sec) * 1000 + (end_time.tv_usec - start_time.tv_usec)/1000;
    if (time_val > 0) {
        printf("total time is :%lf(seconds), count:%d, times/perseconds:%ld\n", 
           (double) time_val/1000, md5_max_times, (md5_max_times/time_val)*1000);
    } else {
        printf("run time too short\n");
    }
    printf("<===========end performance test md5 for url:%s\n", search_url);



    printf("\n============>test redis subscribe\n");
    char *subscribe_cmd = "SUBSCRIBE channel1.1";
    int subscirbe_cnt = 0;
    r = redisconn_run_command(ctx, subscribe_cmd, strlen(subscribe_cmd)); 
    if (!r) {
        printf("run command failed:%s\n", subscribe_cmd);
        goto out;
    }
    redisconn_free_result(r);
    printf("start subscribe wait\n");
    sleep(60);
    printf("subscribe wait end\n");
    while(r = redisconn_get_subscribe(ctx)) {
        // consume message
        subscirbe_cnt++;
        printf("NEW, Count(%d)\n", subscirbe_cnt);
        redisconn_print_result(r);
        redisconn_free_result(r);
    }

    printf("<============test redis subscribe\n");

out:
    redisconn_close(ctx);
    return 0;
}

